package com.xc.tool.utils;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


/**
 * <p>项目名称: Stars</p>
 * <p>描述: MD5加密的工具类</p>
 * <P>创建人: 小程</p>
 * <P>创建人邮箱: 779943476@qq.com</p>
 * <p>创建时间: 2019/7/1</p>
 *
 * @version v1.0
 */
public class Md5Utils {

    /**
     * <p>功能描述: 获取文件md5</p>
     * <p>更新人: 小程</p>
     * <p>更新描述: 添加方法</p>
     * <p>更新人邮箱: 779943476@qq.com</p>
     * <p>更新时间: 2019/7/2</p>
     *
     * @param file      传入文件对象
     * @param cacheSize 读取文件缓存大小
     * @return 返回文件的md5值
     */
    public static String getFileMd5(File file, int cacheSize) {
        FileInputStream fileInputStream = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            fileInputStream = new FileInputStream(file);
            byte[] buffer = new byte[cacheSize];
            int length;
            while ((length = fileInputStream.read(buffer)) != -1) {
                md5.update(buffer, 0, length);
            }
            return byte2hex(md5.digest());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * <p>功能描述: 获取文件md5</p>
     * <p>更新人: 小程</p>
     * <p>更新描述: 添加方法</p>
     * <p>更新人邮箱: 779943476@qq.com</p>
     * <p>更新时间: 2019/7/2</p>
     *
     * @param file 传入文件对象
     * @return 返回文件的md5值
     */
    public static String getFileMd5(File file) {
        return getFileMd5(file, 1048576);
    }

    /**
     * <p>功能描述: 获取普通MD5</p>
     * <p>更新人: 小程</p>
     * <p>更新描述: 添加方法</p>
     * <p>更新人邮箱: 779943476@qq.com</p>
     * <p>更新时间: 2019/7/2</p>
     *
     * @param password 待加密的密码
     * @return 返回加密后的密文
     */
    public static String getMD5(String password) {
        return md5Hex(password.getBytes());
    }

    /**
     * md5加密传入盐值
     *
     * @param password 密码
     * @param salt     盐
     * @return md5密文
     */
    public static String getSaltMd5(String password, String salt) {
        return md5Hex((password + salt).getBytes());
    }

    /**
     * md5解密传入盐值
     *
     * @param password 密码
     * @param md5      密文
     * @param salt     盐
     * @return 是否相同, true:相同,false:不相同
     */
    public static boolean verifySaltMd5(String password, String md5, String salt) {
        return md5.equals(md5Hex((password + salt).getBytes()));
    }

    /**
     * <p>功能描述: 对密码进行md5加密，随机加盐</p>
     * <p>更新人: 小程</p>
     * <p>更新描述: 添加方法</p>
     * <p>更新人邮箱: 779943476@qq.com</p>
     * <p>更新时间: 2019/7/2</p>
     *
     * @param password 待加密的密码
     * @return 返回加密后的密文
     */
    public static String getSaltMd5(String password) {
        String salt = StringUtils.random(16);
        password = getSaltMd5(password, salt);
        char[] cs = new char[48];
        for (int i = 0; i < 48; i += 3) {
            cs[i] = password.charAt(i / 3 * 2);
            char c = salt.charAt(i / 3);
            cs[i + 1] = c;
            cs[i + 2] = password.charAt(i / 3 * 2 + 1);
        }
        return new String(cs);
    }

    /**
     * <p>功能描述: 验证密码与md5密文是否相同,密文中获取盐</p>
     * <p>更新人: 小程</p>
     * <p>更新描述: 添加方法</p>
     * <p>更新人邮箱: 779943476@qq.com</p>
     * <p>更新时间: 2019/7/2</p>
     *
     * @param password 未加密的密码
     * @param md5      md5密文
     * @return 是否相同, true:相同,false:不相同
     */
    public static boolean verifySaltMd5(String password, String md5) {
        char[] cs1 = new char[32];
        char[] cs2 = new char[16];
        for (int i = 0; i < 48; i += 3) {
            cs1[i / 3 * 2] = md5.charAt(i);
            cs1[i / 3 * 2 + 1] = md5.charAt(i + 2);
            cs2[i / 3] = md5.charAt(i + 1);
        }
        return verifySaltMd5(password, new String(cs1), new String(cs2));
    }

    /**
     * <p>功能描述: 对二进制数组进行md5加密</p>
     * <p>更新人: 小程</p>
     * <p>更新描述: 添加方法</p>
     * <p>更新人邮箱: 779943476@qq.com</p>
     * <p>更新时间: 2019/7/2</p>
     *
     * @param bytes 二进制数组
     * @return 加密后的字符串密文
     */
    private static String md5Hex(byte[] bytes) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] bs = md5.digest(bytes);
            return byte2hex(bs);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * <p>功能描述: 二行制转字符串</p>
     * <p>更新人: 小程</p>
     * <p>更新描述: 添加方法</p>
     * <p>更新人邮箱: 779943476@qq.com</p>
     * <p>更新时间: 2019/7/2</p>
     *
     * @param b 二进制数组
     * @return 转换后的字符串
     */
    private static String byte2hex(byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1)
                hs = hs + "0" + stmp;
            else
                hs = hs + stmp;
            if (n < b.length - 1)
                hs = hs;
        }
        return hs;
    }


}
